---
title: Operations and processes
summary: End-to-end processing workflows behind the service operation surface.
status: draft
owner: SAIF Doc Gen
last_reviewed: 2026-09-22
---

# Operations and processes

This host performs file I/O, preference/session persistence, image queuing, fax dispatch, and identity/authorization resolution on behalf of its callers. Every one of the 24 operations catalogued on [Operations](operations.md) maps to exactly one processing workflow, documented in full on its own page under `operations/`.

This page is the process catalog and hub. Each process's detailed, step-by-step logic lives in its own page under `operations/`.

## Process catalog

| ID | Process | Entry operation | Trigger | Owning component | Rules |
| --- | --- | --- | --- | --- | --- |
| [OP-001](operations/file-readfile.md) | Read a byte range from a caller-supplied path | [`ReadFile`](contracts/file-service.md#readfile) | Caller invokes `ReadFile` over the `FileService` route. | `SAIF.Services.WCF.Services.FileService.ReadFile` | [BR-WCF-003](business-rules.md#br-wcf-003-readfile-returns-a-fixed-length-buffer), [BR-WCF-004](business-rules.md#br-wcf-004-file-operations-trust-the-caller-supplied-path) |
| [OP-002](operations/file-readentirefile.md) | Read an entire file from a caller-supplied path | [`ReadEntireFile`](contracts/file-service.md#readentirefile) | Caller invokes `ReadEntireFile` over the `FileService` route. | `SAIF.Services.WCF.Services.FileService.ReadEntireFile` | [BR-WCF-004](business-rules.md#br-wcf-004-file-operations-trust-the-caller-supplied-path) |
| [OP-003](operations/file-writefile.md) | Write bytes to a caller-supplied path | [`WriteFile`](contracts/file-service.md#writefile) | Caller invokes `WriteFile` over the `FileService` route, or `FaxService`/`ImagingService` constructs a `FileService` internally and calls `WriteFile` directly. | `SAIF.Services.WCF.Services.FileService.WriteFile` | [BR-WCF-004](business-rules.md#br-wcf-004-file-operations-trust-the-caller-supplied-path) |
| [OP-004](operations/file-deletefile.md) | Delete a file at a caller-supplied path | [`DeleteFile`](contracts/file-service.md#deletefile) | Caller invokes `DeleteFile` over the `FileService` route, or `FaxService` calls it internally to remove a staged temp file. | `SAIF.Services.WCF.Services.FileService.DeleteFile` | [BR-WCF-004](business-rules.md#br-wcf-004-file-operations-trust-the-caller-supplied-path) |
| [OP-005](operations/file-length.md) | Report the length of a caller-supplied path | [`Length`](contracts/file-service.md#length) | Caller invokes `Length` over the `FileService` route. | `SAIF.Services.WCF.Services.FileService.Length` | [BR-WCF-004](business-rules.md#br-wcf-004-file-operations-trust-the-caller-supplied-path) |
| [OP-006](operations/preference-getpreferences.md) | Retrieve a stored preference set | [`GetPreferences`](contracts/preference-service.md#getpreferences) | Caller invokes `GetPreferences` over the `PreferenceService` route. | `SAIF.Services.WCF.Services.PreferenceService.GetPreferences` | [BR-WCF-002](business-rules.md#br-wcf-002-per-request-configuration-and-connection-resolution), [BR-WCF-005](business-rules.md#br-wcf-005-preference-keys-are-case-normalized) |
| [OP-007](operations/preference-savepreferences.md) | Insert, update, or delete a stored preference set | [`SavePreferences`](contracts/preference-service.md#savepreferences) | Caller invokes `SavePreferences` over the `PreferenceService` route. | `SAIF.Services.WCF.Services.PreferenceService.SavePreferences` | [BR-WCF-002](business-rules.md#br-wcf-002-per-request-configuration-and-connection-resolution), [BR-WCF-005](business-rules.md#br-wcf-005-preference-keys-are-case-normalized) |
| [OP-008](operations/preference-getdefaultprinter.md) | Resolve a user's default printer from Active Directory | [`GetDefaultPrinter`](contracts/preference-service.md#getdefaultprinter) | Caller invokes `GetDefaultPrinter` over the `PreferenceService` route. | `SAIF.Services.WCF.Services.PreferenceService.GetDefaultPrinter` | [BR-WCF-012](business-rules.md#br-wcf-012-unknown-user-has-no-default-printer), [BR-WCF-013](business-rules.md#br-wcf-013-default-printer-comes-from-an-ad-attribute) |
| [OP-009](operations/web-context-get.md) | Retrieve and consume a stored web context | [`Get`](contracts/web-context-service.md#get) | Caller invokes `Get` over the `WebContext` route. | `SAIF.Services.WCF.Services.WebContextService.Get` | [BR-WCF-002](business-rules.md#br-wcf-002-per-request-configuration-and-connection-resolution), [BR-WCF-014](business-rules.md#br-wcf-014-web-context-operations-require-identifying-arguments) |
| [OP-010](operations/web-context-save.md) | Replace the stored web context for an application and session | [`Save`](contracts/web-context-service.md#save) | Caller invokes `Save` over the `WebContext` route. | `SAIF.Services.WCF.Services.WebContextService.Save` | [BR-WCF-002](business-rules.md#br-wcf-002-per-request-configuration-and-connection-resolution), [BR-WCF-011](business-rules.md#br-wcf-011-persisted-changes-stamp-a-local-timestamp) |
| [OP-011](operations/web-context-createcontext.md) | Construct a new in-memory web context | [`CreateContext`](contracts/web-context-service.md#createcontext) | Caller invokes `CreateContext` over the `WebContext` route, or `WebContextService.Get` calls it internally when locating the context id. | `SAIF.Services.WCF.Services.WebContextService.CreateContext` | [BR-WCF-015](business-rules.md#br-wcf-015-context-identity-comes-from-a-stored-pid-or-a-new-guid) |
| [OP-012](operations/imaging-queueimage.md) | Reserve an image id and write a document with its index sidecar | [`QueueImage`](contracts/imaging-service.md#queueimage) | Caller invokes `QueueImage` over the `Imaging` route. | `SAIF.Services.WCF.Services.ImagingService.QueueImage` | [BR-WCF-002](business-rules.md#br-wcf-002-per-request-configuration-and-connection-resolution), [BR-WCF-004](business-rules.md#br-wcf-004-file-operations-trust-the-caller-supplied-path) |
| [OP-013](operations/imaging-reserveimageid.md) | Reserve an image id with no accompanying file write | [`ReserveImageId`](contracts/imaging-service.md#reserveimageid) | Caller invokes `ReserveImageId` over the `Imaging` route. | `SAIF.Services.WCF.Services.ImagingService.ReserveImageId` | [BR-WCF-024](business-rules.md#br-wcf-024-image-id-reserved-before-any-file-write) |
| [OP-014](operations/fax-sendfax.md) | Stage a document and dispatch it to each fax recipient | [`SendFax`](contracts/fax-service.md#sendfax) | Caller invokes `SendFax` over the `Fax` route. | `SAIF.Services.WCF.Services.FaxService.SendFax` | [BR-WCF-002](business-rules.md#br-wcf-002-per-request-configuration-and-connection-resolution), [BR-WCF-004](business-rules.md#br-wcf-004-file-operations-trust-the-caller-supplied-path) |
| [OP-015](operations/security-isauthorized.md) | Authorize a user for a role, trying the internal domain first | [`IsAuthorized`](contracts/security-service.md#isauthorized) | Caller invokes `IsAuthorized` over the `Security` route. | `SAIF.Services.WCF.Services.Security.SecurityService.IsAuthorized` | [BR-WCF-018](business-rules.md#br-wcf-018-external-ldap-host-falls-back-to-a-literal-default), [BR-WCF-023](business-rules.md#br-wcf-023-required-arguments-are-presence-checked-before-work) |
| [OP-016](operations/security-isauthorized2.md) | Authorize a user for a role with caller-controlled domain order | [`IsAuthorized2`](contracts/security-service.md#isauthorized2) | Caller invokes `IsAuthorized2` over the `Security` route, or `IsAuthorized` calls it internally with `tryInternalDomainFirst = true`. | `SAIF.Services.WCF.Services.Security.SecurityService.IsAuthorized2` | [BR-WCF-018](business-rules.md#br-wcf-018-external-ldap-host-falls-back-to-a-literal-default), [BR-WCF-023](business-rules.md#br-wcf-023-required-arguments-are-presence-checked-before-work) |
| [OP-017](operations/security-getuser.md) | Resolve a user across Active Directory, WCIS, ADP, and external-user sources in priority order | [`GetUser`](contracts/security-service.md#getuser) | Caller invokes `GetUser` over the `Security` route. | `SAIF.Services.WCF.Services.Security.SecurityService.GetUser` | [BR-WCF-018a](business-rules.md#br-wcf-018a-unmatched-user-is-returned-as-non-existent), [BR-WCF-019a](business-rules.md#br-wcf-019a-external-user-active-and-locked-state-derived-from-one-flag) |
| [OP-018](operations/security-getsaifuserbyuserid.md) | Project an AD principal into a SaifUser, resolving the manager's user id | [`GetSaifUserByUserId`](contracts/security-service.md#getsaifuserbyuserid) | Caller invokes `GetSaifUserByUserId` over the `Security` route. | `SAIF.Services.WCF.Services.Security.SecurityService.GetSaifUserByUserId` | [BR-WCF-024a](business-rules.md#br-wcf-024a-manager-user-id-comes-from-a-second-directory-lookup), [BR-WCF-025a](business-rules.md#br-wcf-025a-saif-domain-user-carries-directory-only-attributes) |
| [OP-019](operations/security-getsaifuserbyemployeeid.md) | Resolve an ADP employee id to a SaifUser via its AD account | [`GetSaifUserByEmployeeId`](contracts/security-service.md#getsaifuserbyemployeeid) | Caller invokes `GetSaifUserByEmployeeId` over the `Security` route. | `SAIF.Services.WCF.Services.Security.SecurityService.GetSaifUserByEmployeeId` | [BR-WCF-023a](business-rules.md#br-wcf-023a-employee-id-lookup-falls-back-to-the-adp-projection), [BR-WCF-028a](business-rules.md#br-wcf-028a-adp-employee-active-only-when-status-is-a) |
| [OP-020](operations/security-getuseridforemployeeid.md) | Resolve an ADP employee id to a plain user id | [`GetUserIdForEmployeeId`](contracts/security-service.md#getuseridforemployeeid) | Caller invokes `GetUserIdForEmployeeId` over the `Security` route. | `SAIF.Services.WCF.Services.Security.SecurityService.GetUserIdForEmployeeId` | [BR-WCF-022a](business-rules.md#br-wcf-022a-missing-employee-resolves-to-an-empty-user-id), [BR-WCF-032](business-rules.md#br-wcf-032-every-security-operation-logs-its-request) |
| [OP-021](operations/security-getexternaluser.md) | Resolve an external user and its primary contact | [`GetExternalUser`](contracts/security-service.md#getexternaluser) | Caller invokes `GetExternalUser` over the `Security` route. | `SAIF.Services.WCF.Services.Security.SecurityService.GetExternalUser` | [BR-WCF-019a](business-rules.md#br-wcf-019a-external-user-active-and-locked-state-derived-from-one-flag), [BR-WCF-020a](business-rules.md#br-wcf-020a-injured-worker-status-from-primary-user-type-code) |
| [OP-022](operations/security-getexternaluserbycustomerid.md) | Resolve the most-recent external user for a customer group and user type | [`GetExternalUserByCustomerId`](contracts/security-service.md#getexternaluserbycustomerid) | Caller invokes `GetExternalUserByCustomerId` over the `Security` route. | `SAIF.Services.WCF.Services.Security.SecurityService.GetExternalUserByCustomerId` | [BR-WCF-019a](business-rules.md#br-wcf-019a-external-user-active-and-locked-state-derived-from-one-flag), [BR-WCF-020a](business-rules.md#br-wcf-020a-injured-worker-status-from-primary-user-type-code) |
| [OP-023](operations/security-getinjuredworkeruserbycustomerid.md) | Resolve the most-recent external injured-worker user for a customer group | [`GetInjuredWorkerUserByCustomerId`](contracts/security-service.md#getinjuredworkeruserbycustomerid) | Caller invokes `GetInjuredWorkerUserByCustomerId` over the `Security` route. | `SAIF.Services.WCF.Services.Security.SecurityService.GetInjuredWorkerUserByCustomerId` | [BR-WCF-019a](business-rules.md#br-wcf-019a-external-user-active-and-locked-state-derived-from-one-flag), [BR-WCF-020a](business-rules.md#br-wcf-020a-injured-worker-status-from-primary-user-type-code) |
| [OP-024](operations/security-getusersbygroup.md) | Expand group membership from Active Directory, optionally recursive and optionally including disabled accounts | [`GetUsersByGroup`](contracts/security-service.md#getusersbygroup) | Caller invokes `GetUsersByGroup` over the `Security` route. | `SAIF.Services.WCF.Services.Security.SecurityService.GetUsersByGroup` | [BR-WCF-032](business-rules.md#br-wcf-032-every-security-operation-logs-its-request), [BR-WCF-035](business-rules.md#br-wcf-035-missing-group-returns-null-not-empty-array) |

## Cross-process flow diagram

The following diagram visualizes how processes sequence across a request, including the two internal-delegation chains: `ImagingService.QueueImage` writing through `FileService.WriteFile` twice, and `FaxService.SendFax` writing then deleting a staged file through `FileService`.

```mermaid
flowchart TD
    OP012["OP-012 QueueImage"] --> OP003a["OP-003 WriteFile (document)"]
    OP012 --> OP003b["OP-003 WriteFile (.idx sidecar)"]
    OP014["OP-014 SendFax"] --> OP003c["OP-003 WriteFile (staged document)"]
    OP014 --> LEGACYFAX["Legacy.Fax SendFax (per recipient)"]
    OP014 --> OP004["OP-004 DeleteFile (staged document)"]
    OP015["OP-015 IsAuthorized"] --> OP016["OP-016 IsAuthorized2"]
    OP016 --> ADSVC["ADService / AuthorizationCacheService"]
```

## Transaction boundaries

| Process | Unit of work | Commit point | Shared/cached state |
| --- | --- | --- | --- |
| [OP-006](operations/preference-getpreferences.md) | `OracleUnitOfWorkFactory` (`CLM`) | Not applicable — this is a read outside `Begin`/`Commit` | None |
| [OP-007](operations/preference-savepreferences.md) | `OracleUnitOfWorkFactory` (`CLM`) | `unitOfWork.Commit()` after the add/delete/update decision | None |
| [OP-009](operations/web-context-get.md) | `SqlServerUnitOfWorkFactory` (`NETFRAMEWORK`/`APPM`) | `unitOfWork.Commit()` after the delete loop | None |
| [OP-010](operations/web-context-save.md) | `SqlServerUnitOfWorkFactory` (`NETFRAMEWORK`/`APPM`) | `unitOfWork.Commit()` after the delete-then-insert sequence | None |
| [OP-012](operations/imaging-queueimage.md) | `OracleUnitOfWorkFactory` (`IMG`) for the id reservation; no transaction wraps the file writes | Not applicable — no `Begin`/`Commit` around the file-system work | None |
| [OP-013](operations/imaging-reserveimageid.md) | `OracleUnitOfWorkFactory` (`IMG`) | Not applicable — no transaction | None |
| [OP-015](operations/security-isauthorized.md) | `OracleUnitOfWorkFactory` (`EXTUR`), opened but not used for this decision path | Not applicable | Reads and, on a cache miss, mutates the process-wide `AuthorizationCacheService` cache and the mutable `ldap_external` field |
| [OP-016](operations/security-isauthorized2.md) | `OracleUnitOfWorkFactory` (`EXTUR`), opened but not used for this decision path | Not applicable | Reads and, on a cache miss, mutates the process-wide `AuthorizationCacheService` cache and the mutable `ldap_external` field |
| [OP-017](operations/security-getuser.md) | `OracleUnitOfWorkFactory` (`EXTUR`) | Not applicable — read-only across all sources | None |
| [OP-018](operations/security-getsaifuserbyuserid.md) | `OracleUnitOfWorkFactory` (`EXTUR`), opened but not used for this path | Not applicable | None |
| [OP-019](operations/security-getsaifuserbyemployeeid.md) | `OracleUnitOfWorkFactory` (`EXTUR`) | Not applicable — read only | None |
| [OP-020](operations/security-getuseridforemployeeid.md) | `OracleUnitOfWorkFactory` (`EXTUR`) | Not applicable — read only | None |
| [OP-021](operations/security-getexternaluser.md) | `OracleUnitOfWorkFactory` (`EXTUR`) | Not applicable — read only | None |
| [OP-022](operations/security-getexternaluserbycustomerid.md) | `OracleUnitOfWorkFactory` (`EXTUR`) | Not applicable — read only | None |
| [OP-023](operations/security-getinjuredworkeruserbycustomerid.md) | `OracleUnitOfWorkFactory` (`EXTUR`) | Not applicable — read only | None |
| [OP-024](operations/security-getusersbygroup.md) | None for this path | Not applicable | None |

## Failure and edge-case behavior
- A `FileService` filesystem failure (any of `ReadFile`, `ReadEntireFile`, `WriteFile`, `DeleteFile`, `Length`) surfaces as a generic SOAP fault with full exception detail, including the resolved path, because `includeExceptionDetailInFaults="true"` — see [Faults and error pipeline](faults.md).
- `ImagingService.QueueImage` writing the document succeeds but writing the `.idx` sidecar fails leaves an unindexed document on disk with no compensating rollback.
- `FaxService.SendFax` failing mid-loop across multiple recipients leaves the temporary staged file on disk, because the delete call is not wrapped in a `finally` block.
- `SecurityService.IsAuthorized`/`IsAuthorized2` answer `false` for a missing group, a missing user, or an explicitly disabled account rather than faulting; any other `SecurityException` is rethrown and reaches the caller as a generic SOAP fault.
- Authorization answers are cached per user/role/domain for a configured TTL, so a membership revoked after caching remains authorized until the cache entry expires.

## Related documentation
- [Index](index.md)
- [Overview](overview.md)
- [Architecture](architecture.md)
- [Activation and hosting](activation-hosting.md)
- [Operations](operations.md)
- [Faults and error pipeline](faults.md)
- [Authentication and authorization](authentication-authorization.md)
- [Dependencies](dependencies.md)
- [Configuration](configuration.md)
- [Business rules](business-rules.md)
- [Data model](data-model.md)
- [Operational runbook](operational-runbook.md)
- [Tech debt](tech-debt.md)

## Sources
- src/WCF/SAIF.Services.WCF.Host/Services/FileService.cs
- src/WCF/SAIF.Services.WCF.Host/Services/PreferenceService.cs
- src/WCF/SAIF.Services.WCF.Host/Services/WebContextService.cs
- src/WCF/SAIF.Services.WCF.Host/Services/ImagingService.cs
- src/WCF/SAIF.Services.WCF.Host/Services/FaxService.cs
- src/WCF/SAIF.Services.WCF.Host/Services/Security/SecurityService.cs
